#ifndef DELEGATE_H_
#define DELEGATE_H_
#include <typeinfo>
#include <vector>
#include <list>
#include <map>
#include <functional>

template<typename ReturnType, typename ...ParamType>
class HKEvent;

template<typename ReturnType, typename ...ParamType>
class IDelegate
{
public:
    typedef std::map<HKEvent<ReturnType, ParamType...>*, bool> EventMap;
    typedef typename EventMap::iterator EventIterator;
    typedef typename EventMap::const_iterator ConstEventIterator;
    IDelegate();
    virtual ~IDelegate();
    virtual bool isType(const std::type_info& _type) = 0;
    virtual ReturnType invoke(ParamType... params) = 0;
    virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const;
    friend class HKEvent<ReturnType, ParamType...>;
private:
    int count = 0;
    EventMap events;
};

//普通函数委托
template<typename ReturnType, typename ...ParamType>
class CStaticDelegate :public IDelegate<ReturnType, ParamType...>
{
public:
    typedef  ReturnType(__stdcall *Func)(ParamType...,void*);

    CStaticDelegate(Func _func, void* _usrHandle);

    virtual bool isType(const std::type_info& _type);

    virtual ReturnType invoke(ParamType... params);

    virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const;

    virtual ~CStaticDelegate();
private:
    Func m_Func=nullptr;
    void* m_UsrData=nullptr;
};

//成员函数委托
template<typename T, typename ReturnType, typename ...ParamType>
class CMethodDelegate :public IDelegate<ReturnType, ParamType...>
{
public:
    typedef ReturnType(T::*Method)(ParamType...);

    CMethodDelegate(T * _object, Method _method);

    virtual bool isType(const std::type_info& _type);

    virtual ReturnType invoke(ParamType... params);

    virtual bool compare(IDelegate<ReturnType, ParamType...> *_delegate) const;

    CMethodDelegate();
    virtual ~CMethodDelegate();
private:
    T * m_Object=nullptr;
    Method m_Method=nullptr;
};
///*
template<typename ReturnType, typename ...ParamType>
class CallableMeta:public IDelegate<ReturnType, ParamType...>
{
public:
    CallableMeta(std::function<ReturnType(ParamType...)> _func);

    virtual bool isType(const std::type_info& _type);

    virtual ReturnType invoke(ParamType... params);

    virtual bool compare(IDelegate<ReturnType, ParamType ...> *_delegate)const;

    virtual ~CallableMeta();
private:
    std::function<ReturnType(ParamType...)> m_caller;
};

//事件(事件可以看作是委托的代理,事件依托于委托,无法单独使用)
template<typename ReturnType, typename ...ParamType>
class HKEvent
{
public:
    typedef std::list<IDelegate<ReturnType, ParamType...>*> ListDelegate;
    typedef typename ListDelegate::iterator ListDelegateIterator;
    typedef typename ListDelegate::const_iterator ConstListDelegateIterator;

    HKEvent();

    ~HKEvent();

    bool isEmpty() const;

    void clear();

    HKEvent<ReturnType, ParamType...>& operator+=(IDelegate<ReturnType, ParamType...>* _delegate);

    HKEvent<ReturnType, ParamType...>& operator-=(IDelegate<ReturnType, ParamType...>* _delegate);

    std::vector<ReturnType> operator()(ParamType... params);
private:
    HKEvent<ReturnType, ParamType...>(const HKEvent& _event)=delete;
    HKEvent<ReturnType, ParamType...>& operator=(const HKEvent& _event)=delete;

private:
    ListDelegate m_ListDelegates;
};

//事件
template< typename ...ParamType>
class HKEvent<void, ParamType...>
{
public:
    typedef std::list<IDelegate<void, ParamType...>*> ListDelegate;
    typedef typename ListDelegate::iterator ListDelegateIterator;
    typedef typename ListDelegate::const_iterator ConstListDelegateIterator;

    HKEvent();
    ~HKEvent();

    bool isEmpty() const;

    void clear();

    HKEvent<void, ParamType...>& operator+=(IDelegate<void, ParamType...>* _delegate);

    HKEvent<void, ParamType...>& operator-=(IDelegate<void, ParamType...>* _delegate);

    void operator()(ParamType... params);
private:
    HKEvent<void, ParamType...>(const HKEvent& _event)=delete;
    HKEvent<void, ParamType...>& operator=(const HKEvent& _event)=delete;

private:
    ListDelegate m_ListDelegates;
};

template<class ReturnType, class ...ParamType>
inline IDelegate<ReturnType, ParamType...>* newDelegate(ReturnType(__stdcall *_func)(ParamType...))
{
    return new CStaticDelegate<ReturnType, ParamType...>(_func);
}

template<class ReturnType, class ...ParamType>
inline IDelegate<ReturnType, ParamType...>* newCallableDelegate(std::function<ReturnType(ParamType...)> _func)
{
    return new CallableMeta<ReturnType, ParamType...>(_func);
}

template<class T, class ReturnType, class ...ParamType>
inline IDelegate<ReturnType, ParamType...>* newMethodDelegate(T* _object, ReturnType(T::*_method)(ParamType...))
{
    return new CMethodDelegate<T, ReturnType, ParamType...>(_object, _method);
}

#endif
